package com.soccertgc.core.game 
{
	import com.soccertgc.core.DispatcherDataObject;
	import com.soccertgc.logging.Logger;
	
	import flash.events.Event;	

	public class GameCards extends DispatcherDataObject
	{
	
		// -------------------------------------------------------------------------------
		// CONSTANTS
		// -------------------------------------------------------------------------------

		// JSON property names
		protected static const		JSON_PROPERTY_CARD_COUNT:String				= "numHand";
		protected static const		JSON_PROPERTY_GRAVEYARD_CARD_COUNT:String	= "numGrave";
		protected static const		JSON_PROPERTY_DECK_CARD_COUNT:String		= "numDeck";
		protected static const		JSON_PROPERTY_MAX_PLAYABLE:String			= "maxPlay";
		protected static const		JSON_PROPERTY_MAX_DISCARDABLE:String		= "maxDiscard";
		protected static const		JSON_PROPERTY_HAND:String					= "cardList";
		protected static const		JSON_PROPERTY_GRAVEYARD:String				= "graveList";
		

		// Default values
		protected static const      DEFAULT_CARD_COUNT:uint						= 0;
		protected static const      DEFAULT_GRAVEYARD_CARD_COUNT:uint			= 0;
		protected static const      DEFAULT_DECK_CARD_COUNT:uint				= 0;
		protected static const      DEFAULT_MAX_PLAYABLE:uint					= GameOptions.DEFAULT_HAND_SIZE;
		protected static const      DEFAULT_MAX_DISCARDABLE:uint				= GameOptions.DEFAULT_DISCARD_SIZE;
		
		// Events
		public static const         EVENT_HAND_CHANGED:String					= "game_hand_changed";
		public static const         EVENT_GRAVEYARD_CHANGED:String				= "game_graveyard_changed";
		
		// -------------------------------------------------------------------------------
		// FIELDS
		// -------------------------------------------------------------------------------
		
		private var _cardCount:uint;
		private var _graveyardCardCount:uint;
		private var _deckCardCount:uint;
		private var _maxPlayable:uint;
		private var _maxDiscardable:uint;
		private var _hand:Vector.<GameActionCard>;
		private var _graveyard:Vector.<GameActionCard>;
		
		private var	_gameTeam:GameTeam; // Game reference
		
		// -------------------------------------------------------------------------------
		// CONSTRUCTOR
		// -------------------------------------------------------------------------------
		
		public function GameCards(gameTeam:GameTeam, data:Object = null)
		{
			// Ancestor constructor
			super();
			// GameTeam reference
			_gameTeam = gameTeam;
			// Init objects
			_hand = new Vector.<GameActionCard>();
			_graveyard = new Vector.<GameActionCard>();
			// init data
			clear();
			// If data is provided, initializes the instance
			if (data != null) load(data);
		}
		
		// -------------------------------------------------------------------------------
		// PROPERTIES
		// -------------------------------------------------------------------------------
		
		public function get cardCount():uint
		{
			return _cardCount;
		}
		
		public function set cardCount(value:uint):void
		{
			_cardCount = value;
		}
		
		public function get graveyardCardCount():uint
		{
			return _graveyardCardCount;
		}
		
		public function set graveyardCardCount(value:uint):void
		{
			_graveyardCardCount = value;
		}
		
		public function get deckCardCount():uint
		{
			return _deckCardCount;
		}
		
		public function set deckCardCount(value:uint):void
		{
			_deckCardCount = value;
		}
		
		public function get maxPlayable():uint
		{
			return _maxPlayable;
		}
		
		public function set maxPlayable(value:uint):void
		{
			_maxPlayable = value;
		}
		
		public function get maxDiscardable():uint
		{
			return _maxDiscardable;
		}
		
		public function set maxDiscardable(value:uint):void
		{
			_maxDiscardable = value;
		}
		
		public function get hand():Vector.<GameActionCard>
		{
			return _hand;
		}
		
		public function get graveyard():Vector.<GameActionCard>
		{
			return _graveyard;
		}
		
		// -------------------------------------------------------------------------------
		// PRIVATE METHODS
		// -------------------------------------------------------------------------------
		
		// DataObject implementation
		
		override protected function validate(data:Object):void
		{
			// Standard required data
			if (!data.hasOwnProperty(JSON_PROPERTY_CARD_COUNT)) 			throwLoadMissingPropError(JSON_PROPERTY_CARD_COUNT);
			if (!data.hasOwnProperty(JSON_PROPERTY_GRAVEYARD_CARD_COUNT)) 	throwLoadMissingPropError(JSON_PROPERTY_GRAVEYARD_CARD_COUNT);
			if (!data.hasOwnProperty(JSON_PROPERTY_DECK_CARD_COUNT)) 		throwLoadMissingPropError(JSON_PROPERTY_DECK_CARD_COUNT);
			// If the team that owns the cards is the player, player data are required
			if (_gameTeam.isPlayerTeam)
			{
				if (!data.hasOwnProperty(JSON_PROPERTY_MAX_PLAYABLE)) 		throwLoadMissingPropError(JSON_PROPERTY_MAX_PLAYABLE);
				if (!data.hasOwnProperty(JSON_PROPERTY_MAX_DISCARDABLE)) 	throwLoadMissingPropError(JSON_PROPERTY_MAX_DISCARDABLE);
				if (!data.hasOwnProperty(JSON_PROPERTY_HAND)) 				throwLoadMissingPropError(JSON_PROPERTY_HAND);
				// if (!data.hasOwnProperty(JSON_PROPERTY_GRAVEYARD)) 			throwLoadMissingPropError(JSON_PROPERTY_GRAVEYARD);
			}
		}
		
		override protected function fill(data:Object):void
		{
			// Locals
			var i:int = 0;
			var j:int = 0;
			var instanceId:uint = 0;
			var message:String;
			var actionCard:GameActionCard;
			// Standard data
			_cardCount 			= data[JSON_PROPERTY_CARD_COUNT];
			_graveyardCardCount = data[JSON_PROPERTY_CARD_COUNT];
			_cardCount 			= data[JSON_PROPERTY_CARD_COUNT];
			// Hand limit data
			if (data.hasOwnProperty(JSON_PROPERTY_MAX_PLAYABLE))
			{
				_maxPlayable = data[JSON_PROPERTY_MAX_PLAYABLE];
			}
			if (data.hasOwnProperty(JSON_PROPERTY_MAX_DISCARDABLE))
			{
				_maxDiscardable = data[JSON_PROPERTY_MAX_DISCARDABLE];
			}
			// Hand data
			if (data.hasOwnProperty(JSON_PROPERTY_HAND))
			{
				// Raw data
				var raw_hand:Array = data[JSON_PROPERTY_HAND];
				// Temporary action card list
				var hand:Vector.<GameActionCard> = new Vector.<GameActionCard>();
				// Loop over raw data
				for (i = 0; i<raw_hand.length; i++)
				{
					// Retrieve the action card instance id
					instanceId = raw_hand[i];
					// Retrieve the card data from the game deck
					actionCard = _gameTeam.game.deck.findActionCard(instanceId);
					// Check card reference
					if (actionCard != null)
					{
						// Add the card to the list
						hand.push(actionCard);
					}
					else
					{
						// ERROR > Card not faound!
						message = "GameActionsCard (id:" + instanceId + ") not found in Deck linked to the game!";
						Logger.error(message);
						throw new Error(message);
					}
				}
				// Clear and popolate graveyard card list
				_hand.splice(0, _hand.length);
				for (j = 0; j < hand.length; j++)
				{
					_hand.push(hand[j]);
				}	
				// Dispatch EVENT_HAND_CHANGED
				dispatchHandChanged();
			}
			// Graveyard data
			if (data.hasOwnProperty(JSON_PROPERTY_GRAVEYARD))
			{
				// Raw data
				var raw_graveyard:Array = data[JSON_PROPERTY_GRAVEYARD];
				// Temporary action card list
				var graveyard:Vector.<GameActionCard> = new Vector.<GameActionCard>();
				// Loop over raw data
				for (var k:int = 0; k<raw_graveyard.length; k++)
				{
					// Retrieve the action card instance id
					instanceId = raw_graveyard[k];
					// Retrieve the card data from the game deck
					actionCard = _gameTeam.game.deck.findActionCard(instanceId);
					// Check card reference
					if (actionCard != null)
					{
						// Add the card to the list
						graveyard.push(actionCard);
					}
					else
					{
						// ERROR > Card not faound!
						message = "GameActionsCard (id:" + instanceId + ") not found in Deck linked to the game!";
						Logger.error(message);
						throw new Error(message);
					}
				}
				// Clear and popolate graveyard card list
				_graveyard.splice(0, _graveyard.length);
				for (j = 0; j < graveyard.length; j++)
				{
					_graveyard.push(graveyard[j]);
				}	
				// Dispatch EVENT_GRAVEYARD_CHANGED
				dispatchGraveyardChanged();
			}
		}
		
		// Event dispatchers
		
		protected function dispatchHandChanged():void
        {
			dispatchEvent(new Event(EVENT_HAND_CHANGED));
        }
		
		protected function dispatchGraveyardChanged():void
		{
			dispatchEvent(new Event(EVENT_GRAVEYARD_CHANGED));
		}
		
		// -------------------------------------------------------------------------------
		// PUBLIC METHODS
		// -------------------------------------------------------------------------------
		
		public function equals(gameCards:GameCards):Boolean
		{
			// Check data
			if (_cardCount			!= gameCards.cardCount 			||
				_graveyardCardCount	!= gameCards.graveyardCardCount ||
				_deckCardCount		!= gameCards.deckCardCount 		||
				_maxPlayable		!= gameCards.maxPlayable 		||
				_maxDiscardable		!= gameCards.maxDiscardable		||
				_hand.length 		!= gameCards.hand.length		||
				_graveyard.length 	!= gameCards.graveyard.length) return false;
			// Loop over hand action cards
			for (var i:int = 0; i < _hand.length; i++)
			{
				if (!_hand[i].equals(gameCards.hand[i])) return false;
			}
			// Loop over graveyard action cards
			for (var j:int = 0; j < _graveyard.length; j++)
			{
				if (!_graveyard[j].equals(gameCards.graveyard[j])) return false;
			}
			// Instances are equal
			return 	true;
		}
		
		public function update(gameCards:GameCards):void
		{
			// Check data
			_cardCount			= gameCards.cardCount;
			_graveyardCardCount	= gameCards.graveyardCardCount;
			_deckCardCount		= gameCards.deckCardCount;
			_maxPlayable		= gameCards.maxPlayable;
			_maxDiscardable		= gameCards.maxDiscardable;
			// Loop over hand action cards
			var h:Vector.<GameActionCard> = new Vector.<GameActionCard>();
			for (var i:int = 0; i < gameCards.hand.length; i++)
			{
				h.push(_gameTeam.game.deck.findActionCard(gameCards.hand[i].instanceId));
			}
			// Loop over graveyard action cards
			var g:Vector.<GameActionCard> = new Vector.<GameActionCard>();
			for (var j:int = 0; j < gameCards.graveyard.length; j++)
			{
				g.push(_gameTeam.game.deck.findActionCard(gameCards.graveyard[j].instanceId));
			}
			// Sets hand cards
			_hand.splice(0, _hand.length);
			for (var x:int = 0; x < gameCards.hand.length; x++) _hand.push(h[x]);
			// Sets graveyard cards
			_graveyard.splice(0, _graveyard.length);
			for (var y:int = 0; y < graveyard.length; y++) _graveyard.push(g[y]);
		}
		
		public function copy(gameCards:GameCards):void
		{
			// CHeck same game deck
			if (_gameTeam != gameCards._gameTeam) throw new Error("Cannot copy from cards of a different GameTeam");
			// Check data
			_cardCount			= gameCards.cardCount;
			_graveyardCardCount	= gameCards.graveyardCardCount;
			_deckCardCount		= gameCards.deckCardCount;
			_maxPlayable		= gameCards.maxPlayable;
			_maxDiscardable		= gameCards.maxDiscardable;
			// Sets hand cards
			_hand.splice(0, _hand.length);
			for (var x:int = 0; x < gameCards.hand.length; x++) _hand.push(gameCards.hand[x]);
			// Sets graveyard cards
			_graveyard.splice(0, _graveyard.length);
			for (var y:int = 0; y < graveyard.length; y++) _graveyard.push(gameCards.graveyard[y]);
		}
		
		public function clone():GameCards
		{
			var cards:GameCards = new GameCards(_gameTeam);
			cards.copy(this);
			return cards;
		}
		
		public function duplicate():GameCards
		{
			var cards:GameCards = new GameCards(_gameTeam);
			cards.clear();
			return cards;
		}
		
		override public function clear():void
		{
			// Clear data
			_cardCount			= DEFAULT_CARD_COUNT;
			_graveyardCardCount	= DEFAULT_GRAVEYARD_CARD_COUNT;
			_deckCardCount		= DEFAULT_DECK_CARD_COUNT;
			_maxPlayable		= DEFAULT_MAX_PLAYABLE;
			_maxDiscardable		= DEFAULT_MAX_DISCARDABLE;
			// Clear objects
			_hand.splice(0, _hand.length);
			_graveyard.splice(0, _graveyard.length);
		}
	
	}
	
}